/// ****************************************************************************
/// Author:	        Robin Zhu
/// Create Date:	2011-11-1
/// Purpose: 		数据操作执行类（Microsoft SQL Server版本）文件
/// ****************************************************************************
/// Modify By		Date			Remark
/// Robin           2012-4-3        当插入有Identity字段的记录时，使用transaction防止关闭连接，以便取到Identity的值
/// ****************************************************************************

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Common;
using System.Data.SqlClient;
using System.Data;
using System.Linq.Expressions;

namespace RB.DataAccess.SqlServer
{
    /// <summary>
    /// 数据操作执行类（Microsoft SQL Server版本）
    /// </summary>
    public class MsSqlExecutor : Executor
    {
        public MsSqlExecutor(MsSqlDataContext dataContext)
            : base(dataContext)
        {

        }

        /// <summary>
        /// 插入新记录，如果有Identity字段，则返回该字段的值
        /// </summary>
        /// <typeparam name="T">类型</typeparam>
        /// <param name="entity">实体对象实例</param>
        /// <param name="mappingTo">映射到另一个表，默认为空，表示使用类型T获取表名</param>
        /// <returns>插入的记录数</returns>
        public override int Insert<T>(T entity, string mappingTo)
        {
            var identityField = TypeMapper<T>.AutoIncrementField;

            bool bTrans = IsTransactionBegin();
            if (identityField != null && !bTrans)
                BeginTransaction();

            int result = 0;
            try
            {
                result = Insert<T, T>(p => entity, mappingTo);

                if (identityField != null)
                {
                    object oid = ExecuteScalar("SELECT SCOPE_IDENTITY()");
                    int id = Convert.ToInt32(oid);
                    identityField.SetValue(entity, id, null);

                    if (!bTrans)
                        CommitTransaction();
                }
            }
            catch
            {
                if (identityField != null && !bTrans)
                    RollbackTransaction();
                throw;
            }
            return result;
        }

        public override int Insert<T, TFields>(Expression<Func<T, TFields>> fields, string mappingTo)
        {
            TypeMapper<T>.UseNativeAutoIncrement();

            int n = 0;
            try
            {
                n = base.Insert<T, TFields>(fields, mappingTo);
            }
            catch (SqlException e)
            {
                if (e.Number == 2627)
                    throw new PrimaryKeyException(e);
                else
                    throw;
            }
            return n;
        }

        public override int Insert<TFields>(IQueryable<TFields> query, string mappingTo)
        {
            int n = 0;
            try
            {
                n = base.Insert<TFields>(query, mappingTo);
            }
            catch (SqlException e)
            {
                if (e.Number == 2627)
                    throw new PrimaryKeyException(e);
                else
                    throw;
            }
            return n;
        }

        public override int Update<T, TFields>(Expression<Func<T, TFields>> fields, Expression<Func<T, bool>> predict, string mappingTo)
        {
            TypeMapper<T>.UseNativeAutoIncrement();

            int n = 0;
            try
            {
                n = base.Update<T, TFields>(fields, predict, mappingTo);
            }
            catch (SqlException e)
            {
                if (e.Number == 2627)
                    throw new PrimaryKeyException(e);
                else
                    throw;
            }

            return n;
        }

        public override int Update<T, TFields>(Expression<Func<T, TFields>> fields, IQueryable<T> query)
        {
            TypeMapper<T>.UseNativeAutoIncrement();

            int n = 0;
            try
            {
                n = base.Update<T, TFields>(fields, query);
            }
            catch (SqlException e)
            {
                if (e.Number == 2627)
                    throw new PrimaryKeyException(e);
                else
                    throw;
            }

            return n;
        }
    }
}
